package com.yilin.tms.capital.service.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yilin.tms.capital.commons.cmbc.CmbcResData;
import com.yilin.tms.capital.service.IBankCardService;
import com.yilin.tms.capital.service.ICmbcService;
import com.yilin.tms.capital.service.ITradeFlowService;
import com.yilin.tms.capital.service.ITradeRecordService;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.util.ArrayUtil;
import com.yilin.commons.util.DateTimeUtil;
import com.yilin.commons.util.MapUtil;
import com.yilin.tms.core.application.PlatRequest;
import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.entity.capital.BankCard;
import com.yilin.tms.core.entity.capital.TradeRecord;
import com.yilin.tms.core.entity.user.account.Account;
import com.yilin.tms.core.entity.user.hatch.HatchPlatProduct;
import com.yilin.tms.core.remote.IOrderRemote;
import com.yilin.tms.core.remote.IUserRemote;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
public class CmbcService implements ICmbcService {

    private  Logger logger = LoggerFactory.getLogger(AlipayService.class);

    @Resource
    IUserRemote userRemote;
    @Resource
    IBankCardService bankCardService;
    @Resource
    IOrderRemote orderRemote;
    @Resource
    ITradeRecordService tradeRecordService;
    @Resource
    ITradeFlowService tradeFlowService;

    //TODO   ==============================================交易模块=================================================================

    /**
     * 创建人：yhp 时间：2023年7月6日09:40:48   功能：  转账交易(Xfer，batchXfer)
     * 备注:批量付款付款人必须同一个，并且必须传批量单号  适用与运单支付
     * @param tradeRecordList 支付单 注： 必须包含付款人银行卡和收款人银行卡
     */
    @Override
    public List<TradeRecord> transferXfer(List<TradeRecord> tradeRecordList, Account loginUser) {
        boolean hasDifferentIds = tradeRecordList.stream().map(TradeRecord::getPaymentOrganizeId).distinct().count() > 1;
        if (hasDifferentIds) throw new BusinessException("存在付款人不一致，禁止批量付款！");
        HatchPlatProduct platProduct = ParamUtil.isSuccess(userRemote.getPlatProductHatch(ArrayUtil.first(tradeRecordList).getPlatId()));
        ParamUtil.isNull(platProduct, "获取平台配置信息失败");
        CmbcResData cmbcResData=null  ;
        CmbcResData cmbcResDataPrivate=null ;
        List<TradeRecord> tradeRecordsOne=new ArrayList<>();
        List<TradeRecord> tradeRecordsPrivate=new ArrayList<>();
        if (tradeRecordList.size() == 1) {//单条
            TradeRecord tradeRecord = ArrayUtil.first(tradeRecordList);
            boolean isSpanBank= !tradeRecord.getPaymentBackCard().getBankShortName().equals(tradeRecord.getCollectionBackCard().getBankShortName());
            updateTradeRecord(tradeRecord, tradeRecordList.get(0).getPaymentBackCard().getBankAccNo());
            tradeRecordService.updateById(tradeRecord);
            tradeRecordsOne.add(tradeRecord);
            boolean isRefund = tradeRecord.getTradeType() == TradeRecord.TradeType.refund;
             cmbcResData = PlatRequest.request(loginUser.getToken(), platProduct.getNetworkFreightUrl() + "/platform/cmbc/transferXfer", MapUtil.generate(paramMap -> {
                paramMap.put("tradeNo", tradeRecord.getTradeNo());
                paramMap.put("tradeName", tradeRecord.getTransName());
                paramMap.put("outAcctNo", tradeRecord.getPaymentBackCard().getBankAccNo());
                paramMap.put("outAcctName", tradeRecord.getPaymentBackCard().getHoldCardName());
                paramMap.put("inAcctNo", tradeRecord.getCollectionBackCard().getBankAccNo());
                paramMap.put("inAcctName", tradeRecord.getCollectionBackCard().getHoldCardName());
                paramMap.put("externBank", isSpanBank ?  "1":"0");
                paramMap.put("localFlag", isSpanBank ? (tradeRecord.getMoney() >= 1000000 ? "3" : "2"): "0");
                paramMap.put("rcvCustType", tradeRecord.getCollectionBackCard().getBankAccType() == BankCard.BankAccType.businessAcc ? "1" : "2");
                paramMap.put("bankCode", tradeRecord.getCollectionBackCard().getBankCode());
                paramMap.put("bankName", tradeRecord.getCollectionBackCard().getOpenBankName());
                paramMap.put("bankAddr", tradeRecord.getCollectionBackCard().getOpenAddress());
                paramMap.put("areaCode", tradeRecord.getCollectionBackCard().getCityCode());
                paramMap.put("tranAmount", tradeRecord.getMoney());
                paramMap.put("explain", isRefund ? "375" : "394"); //394 其他合法收入——运费 375 其他合法收入——资金退还
                paramMap.put("certNo", tradeRecord.getTradeCode());
                paramMap.put("remark", tradeRecord.getRemark()); //备注
            }), new TypeToken<CmbcResData>() {
            });
        } else {//大批量付款
            List<Map<String, Object>> mapList = new ArrayList<>();
            List<Map<String, Object>> mapListPrivate = new ArrayList<>();
            String batchTradeNo = DateTimeUtil.dateNo("BT");
            String batchTradeNoPrivate = DateTimeUtil.dateNo("DF");

            for (TradeRecord tradeRecord : tradeRecordList) {
                updateTradeRecord(tradeRecord, tradeRecordList.get(0).getPaymentBackCard().getBankAccNo());
                boolean isRefund = tradeRecord.getTradeType() == TradeRecord.TradeType.refund;
                boolean isSpanBank= tradeRecord.getPaymentBackCard().getBankShortName().equals(tradeRecord.getCollectionBackCard().getBankShortName());
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("tradeNo", tradeRecord.getTradeNo());//   流水号
                paramMap.put("tradeCode", tradeRecord.getTradeCode());// 企业自制凭证号 8位数字
                paramMap.put("acntToNo", tradeRecord.getCollectionBackCard().getBankAccNo()); //收款账号
                paramMap.put("acntToName", tradeRecord.getCollectionBackCard().getHoldCardName()); //收款户名
                paramMap.put("bankCode", tradeRecord.getCollectionBackCard().getBankCode()); //收款行联行号行内转账不用输入大小额时填支付行号网银互联时填写网银互联支付行号
                paramMap.put("openBankName", tradeRecord.getCollectionBackCard().getOpenBankName()); // 收款行名 行内转账不输，跨行转账必须输入。大小额时填写支付行名 网银互联是填写网银互联支付行名
                if (isSpanBank) paramMap.put("localFlag", "0");////汇路 行内交易输入0跨行交易汇路为:6 小额实时支付7 大额实时支付 11 网银互联(暂不支持)
                else paramMap.put("localFlag", tradeRecord.getMoney() >= 1000000 ? "7" : "6");
                paramMap.put("remark", tradeRecord.getRemark()); //备注
                paramMap.put("useTo", isRefund ?"375": "394"); //394 其他合法收入——运费 375 其他合法收入——资金退还
                paramMap.put("amount", tradeRecord.getMoney()); //转账金额
                paramMap.put("tradeName", tradeRecord.getTransName()); //转账金额
                if(isSpanBank&&tradeRecord.getCollectionBackCard().getBankAccType() == BankCard.BankAccType.personCard){
                    paramMap.put("bankType", "0");
                    mapListPrivate.add(paramMap);
                    tradeRecord.setBatchTradeNo(batchTradeNoPrivate);
                    tradeRecordsPrivate.add(tradeRecord);
                }else{
                    paramMap.put("accountType", tradeRecord.getCollectionBackCard().getBankAccType() == BankCard.BankAccType.businessAcc ? "0" : "1");//收款账户类型 必输 0.企业 1.个人卡 2.个人折 1
                    mapList.add(paramMap);
                    tradeRecord.setBatchTradeNo(batchTradeNo);
                    tradeRecordsOne.add(tradeRecord);
                }
            }
            Map<String, Object> jsonContentMap = new HashMap<>();
            jsonContentMap.put("payerAcct", tradeRecordList.get(0).getPaymentBackCard().getBankAccNo());//付款账户
            jsonContentMap.put("payerName", tradeRecordList.get(0).getPaymentBackCard().getHoldCardName());//付款账户
            tradeRecordService.updateBatchById(tradeRecordList);
            if(mapList.size()>0) {
                jsonContentMap.put("collectionList", mapList);// 收款人信息
                jsonContentMap.put("batchNo", batchTradeNo);// 批次单号
                try {
                    cmbcResData=requestPlatForm(loginUser.getToken(),platProduct.getNetworkFreightUrl() + "/platform/cmbc/transferBatchXfer",jsonContentMap);
                } catch (Exception e) {
                    logger.info("批量转账支付异常"+e.getMessage());
                }
            }
            if(mapListPrivate.size()>0){
                jsonContentMap.put("collectionList", mapListPrivate);// 收款人信息
                jsonContentMap.put("batchNo", batchTradeNoPrivate);// 批次单号
                jsonContentMap.put("payType","2");//款类型0:支付1:代发工资2:费用报销
                try {
                    cmbcResDataPrivate=requestPlatForm(loginUser.getToken(),platProduct.getNetworkFreightUrl() + "/platform/cmbc/batchCostReimbNew",jsonContentMap);
                } catch (Exception e) {
                    logger.info("批量费用报销异常："+e.getMessage());
                }
            }
        }
        if(cmbcResData!=null)  updateTradeRecordsList(tradeRecordsOne, loginUser, cmbcResData);
        if(cmbcResDataPrivate!=null) updateTradeRecordsList(tradeRecordsPrivate, loginUser, cmbcResDataPrivate);
        if(tradeRecordsPrivate.size()>0)tradeRecordsOne.addAll(tradeRecordsPrivate);
        tradeRecordService.updateBatchById(tradeRecordsOne);
        return tradeRecordsOne;
        // 支付提交结果

    }


    /**
     * 创建人：yhp 时间：2023年7月6日09:40:48   功能：交易查询(qryXfer,qryBatchXfer)
     */
    @Override
    public TradeRecord transferQryXfer(TradeRecord tradeRecord, Account loginUser) {
        List<TradeRecord> tradeRecordList=new ArrayList<>();
        String token = loginUser == null ? null : loginUser.getToken();
        if (tradeRecord.getBatchTradeNo() == null) tradeRecordList = processSingleTradeRecord(tradeRecord.getId(), token); //单笔
        else if (tradeRecord.getBatchTradeNo() != null) {
             tradeRecordList = processBatchTradeRecord(tradeRecord.getBatchTradeNo(), token);  //多笔
        }
        else throw new BusinessException("tradeRecordId And tradeBatchNo Is Null");
        tradeRecordService.saveOrUpdateBatch(tradeRecordList);
        TradeRecord finalTradeRecords = tradeRecord;
        Optional<TradeRecord> matchedTradeRecord = tradeRecordList.stream().filter(record -> record.getId().equals(finalTradeRecords.getId())).findFirst();
        if (matchedTradeRecord.isPresent()) tradeRecord = matchedTradeRecord.get();
        return tradeRecord;
    }

    ///################################################################################################################################

    //单笔查询
    private List<TradeRecord> processSingleTradeRecord(String tradeRecordId, String token) {
        TradeRecord tradeRecord = tradeRecordService.getTradeRecordById(tradeRecordId);
        HatchPlatProduct hatchPlatProduct = ParamUtil.isSuccess(userRemote.getPlatProductHatch(tradeRecord.getPlatId()));
        ParamUtil.isNull(hatchPlatProduct, "获取平台配置信息失败");
        CmbcResData cmbcResData = PlatRequest.request(token, hatchPlatProduct.getNetworkFreightUrl() + "/platform/cmbc/transferQryXfer", MapUtil.generate(map -> {
            map.put("insId", tradeRecord.getTradeNo());
            map.put("servid", tradeRecord.getBankFlowNo());
        }), new TypeToken<CmbcResData>() {
        });
        Map<String, Object> statusCodeMap = (Map<String, Object>) cmbcResData.getDataMap().get("statusId");
        String statusCode = MapUtil.getMapString(statusCodeMap, "statusCode");
        tradeRecord.setBankFlowNo(MapUtil.getMapString(cmbcResData.getDataMap(), "svrId"));
        if (statusCode.equals("0") || statusCode.equals("5")) {
            tradeRecord.setTradeStatus(TradeRecord.TradeStatus.paySuccess);
            if (tradeRecord.getFinishTime() == null) tradeRecord.setFinishTime(new Date());
        } else if (statusCode.equals("2")) {
            tradeRecord.setTradeStatus(TradeRecord.TradeStatus.payFail);
        } else {
            tradeRecord.setTradeStatus(TradeRecord.TradeStatus.wait);
        }
        tradeRecord.setTradeFailMsg(MapUtil.getMapString(statusCodeMap, "statusErrMsg"));
        return  Collections.singletonList(tradeRecord);
    }

    //批量查询
    private List<TradeRecord> processBatchTradeRecord(String tradeRecordBatchNo, String token) {
        List<TradeRecord> tradeRecordList = tradeRecordService.getTradeRecordListByBatchNo(tradeRecordBatchNo);
        HatchPlatProduct hatchPlatProduct = ParamUtil.isSuccess(userRemote.getPlatProductHatch(ArrayUtil.first(tradeRecordList).getPlatId()));
        ParamUtil.isNull(hatchPlatProduct, "获取平台配置信息失败");
        CmbcResData cmbcResData = PlatRequest.request(token, hatchPlatProduct.getNetworkFreightUrl() + "/platform/cmbc/transferQryBatchXfer", MapUtil.generate(map -> {
            map.put("batchTradeNo", tradeRecordBatchNo);
        }), new TypeToken<CmbcResData>() {});
        List<TradeRecord> tradeRecordListNew = new ArrayList<>();
        Map<String, Object> batchTransfersMap = (Map<String, Object>) cmbcResData.getDataMap().get("batchTransfers");
        String fileContentStr = (String) batchTransfersMap.get("fileContent");
        String[] fileContentStrArrs = fileContentStr.split("\\^");
        for (String fileContent : fileContentStrArrs) {
            String[] content = fileContent.split("\\|");
            String certNo = content[0];//企业自制凭证号
            String paymentAccNo = content[1];//付款人账号32
            String paymentName = content[2];//付款人名称
            String paymentBankName = content[3];//付款人行名4
            String incomeAccNo = content[4];//收款人账号3
            String incomeName = content[5];//收款人名称
            String incomeBankName = content[6];//收款行行名
            String amount = content[7];//金额1
            String status = content[8];//交易状态：1:成功;2:失败
            String erroMsg = content[9];//错误信
            TradeRecord tradeRecordNew = tradeRecordList.stream().filter(tradeRecords -> tradeRecords.getTradeCode().equals(certNo)).findFirst().orElse(null);
            if (tradeRecordNew == null) continue;
            if (status.equals("1")) {
                tradeRecordNew.setTradeStatus(TradeRecord.TradeStatus.paySuccess);
                if(tradeRecordNew.getBankFlowNo()==null)tradeRecordNew.setBankFlowNo(tradeRecordBatchNo);
                if(tradeRecordNew.getFinishTime()==null) tradeRecordNew.setFinishTime(new Date());
            } else if (status.equals("2")) {
                tradeRecordNew.setTradeStatus(TradeRecord.TradeStatus.payFail);
            } else {
                tradeRecordNew.setTradeStatus(TradeRecord.TradeStatus.wait);
            }
            tradeRecordNew.setTradeFailMsg(erroMsg);
            tradeRecordListNew.add(tradeRecordNew);
        }
        return tradeRecordListNew;
    }
    private CmbcResData requestPlatForm(String  token,String pathUrl,Map<String,Object> jsonContentMap){
        CmbcResData  cmbcResData  = PlatRequest.request(token, pathUrl, MapUtil.generate(map -> {
            map.put("jsonContent", new Gson().toJson(jsonContentMap));
        }), new TypeToken<CmbcResData>() {
        });
        return cmbcResData;
    }
    private TradeRecord  updateTradeRecord( TradeRecord tradeRecord,String payAccountNo){
        tradeRecord.setBankType(TradeRecord.BankType.cmbcBankPay);
        tradeRecord.setPaymentCapitalAccount(payAccountNo);
        tradeRecord.setIncomeCapitalAccount( tradeRecord.getCollectionBackCard().getBankAccNo());
        return tradeRecord;
    }
    private List<TradeRecord>  updateTradeRecordsList( List<TradeRecord> tradeRecordList,Account loginUser,CmbcResData cmbcResData){
        Map<String, Object> transferMap = (Map<String, Object>) cmbcResData.getDataMap().get("transfer");
        for (TradeRecord tradeRecord : tradeRecordList) {
            if (transferMap != null) tradeRecord.setBankFlowNo(transferMap.get("svrId").toString());
            tradeRecord.setInitiateTime(new Date());
            tradeRecord.setTradeStatus(TradeRecord.TradeStatus.wait);
            tradeRecord.setOptUserId(loginUser.getId());
            tradeRecord.setOptUserName(loginUser.getName());
        }
        return tradeRecordList;
    }

}
